package org.momo.rpc.bootstrap;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.momo.rpc.annotion.Retry;
import org.momo.rpc.bootstrap.model.ProviderMetaInfo;
import org.momo.rpc.config.RpcConfigLoader;
import org.momo.rpc.config.config.RpcConfig;
import org.momo.rpc.constant.Constant;
import org.momo.rpc.registry.ProviderRegistry;
import org.momo.rpc.provider.ServiceProvider;
import org.momo.rpc.provider.model.ProviderRegistryInfo;
import org.momo.rpc.server.Server;
import org.momo.rpc.extention.ExtensionLoader;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

@Slf4j
public class ProviderBootstrap {

    public static void init(List<ProviderMetaInfo> providerMetaInfos) {
        try {
            // config
            RpcConfigLoader.init();
            RpcConfig rpcConfig = RpcConfigLoader.getRpcConfig();

            // provider 注册中心
            ProviderRegistry providerRegistry = ExtensionLoader.getExtensionLoader(ProviderRegistry.class).getExtension(rpcConfig.getRegistry());
            providerRegistry.initRegistryClient(rpcConfig.getRegistryConfig());

            for(ProviderMetaInfo provider : providerMetaInfos) {
                Class<?> providerClass = provider.getServiceClass();

                // check interface
                Class<?>[] interfaces = providerClass.getInterfaces();
                if(interfaces.length != 1) {
                    log.error("Cannot register service {}, it must can only implement one interface!", providerClass.getName());
                    continue;
                }

                String serviceName = StrUtil.isBlank(provider.getServiceName())? interfaces[0].getName() : provider.getServiceName();
                provider.setServiceName(serviceName);

                // 本地注册服务
                ServiceProvider.provideService(provider);

                // 注册中心注册服务
                ProviderRegistryInfo metaInfo = new ProviderRegistryInfo(provider.getServiceName(), provider.getServiceVersion(), rpcConfig.getServerHost(), rpcConfig.getServerPort());
                providerRegistry.register(metaInfo);

                // 注册非幂等方法
                List<String> retryMethods = new ArrayList<>();
                for(Method method : providerClass.getMethods()) {
                    if(method.isAnnotationPresent(Retry.class)) {
                        Retry retry = method.getAnnotation(Retry.class);
                        if(retry.canRetry()) {
                            retryMethods.add(method.getName());
                        }
                    }
                }
                providerRegistry.registerRetryMethod(provider.getServiceName(), provider.getServiceVersion(), retryMethods);
                log.info("Register service {} {}", provider.getServiceName(), provider.getServiceVersion());
            }

            // 启动服务器
            Server server = ExtensionLoader.getExtensionLoader(Server.class).getExtension(rpcConfig.getServer());
            server.start(rpcConfig.getServerPort());

            // 退出钩子
            Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
            Runtime.getRuntime().addShutdownHook(new Thread(providerRegistry::closeRegistryClient));
        }  catch (IllegalArgumentException e) {
            log.error("Server fail to start, error is {}", e.getMessage());
        } catch (Exception e) {
            log.error("Provider fail to start, error is {}", e.getMessage());
        }
    }
}
